package user

import (
	"database/sql"
	"fmt"
	"log"

	"SkyPath/internal/domain/user/entry"
	userGateway "SkyPath/internal/domain/user/gateway"
	po "SkyPath/internal/infrastructure/gatewayimpl/user/po"
)

// 确保 UserDomainGatewayImpl 实现了 userGateway.UserDomainGateway 接口
var _ userGateway.UserDomainGateway = (*UserDomainGatewayImpl)(nil)

// UserDomainGatewayImpl 实现了用户相关的数据访问逻辑
type UserDomainGatewayImpl struct {
	db *sql.DB
}

// NewUserDomainGatewayImpl 创建一个新的 UserDomainGatewayImpl 实例
func NewUserDomainGatewayImpl(db *sql.DB) *UserDomainGatewayImpl {
	return &UserDomainGatewayImpl{
		db: db,
	}
}

func (u *UserDomainGatewayImpl) SaveUser(user *entry.User) error {
	log.Printf("SaveUser called with user: %+v", user)
	userPo := new(po.UserPO).SetUserPO(user)

	query := `
		INSERT INTO users (id, name, account, password, phone, email, gender, status)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`

	_, err := u.db.Exec(query,
		userPo.Id,
		userPo.Name,
		userPo.Account,
		userPo.Password,
		userPo.Phone,
		userPo.Email,
		userPo.Gender,
		userPo.Status,
	)

	if err != nil {
		return fmt.Errorf("failed to save user: %w", err)
	}

	return nil
}

func (u *UserDomainGatewayImpl) GetUserById(id int) (*entry.User, error) {
	log.Printf("GetUserById called with id: %d", id)
	var userPo po.UserPO

	query := `
		SELECT id, name, account, password, phone, email, gender, status
		FROM users
		WHERE id = $1`

	err := u.db.QueryRow(query, id).Scan(
		&userPo.Id,
		&userPo.Name,
		&userPo.Account,
		&userPo.Password,
		&userPo.Phone,
		&userPo.Email,
		&userPo.Gender,
		&userPo.Status,
	)

	if err == sql.ErrNoRows {
		return nil, nil // 用户不存在
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get user by id: %w", err)
	}

	// 转换为 entry.User 返回
	entryUser := &entry.User{
		Id:      userPo.Id,
		Name:    userPo.Name,
		Account: userPo.Account,
		Phone:   userPo.Phone,
		Email:   userPo.Email,
		Gender:  userPo.Gender,
		Status:  userPo.Status,
	}

	log.Printf("GetUserById: %+v", entryUser)
	return entryUser, nil
}

func (u *UserDomainGatewayImpl) GetUserByAccount(account string) (*entry.User, error) {
	log.Printf("GetUserByAccount called with account: %s", account)
	var userPo po.UserPO

	query := `
		SELECT id, name, account, password, phone, email, gender, status
		FROM users
		WHERE account = $1`

	err := u.db.QueryRow(query, account).Scan(
		&userPo.Id,
		&userPo.Name,
		&userPo.Account,
		&userPo.Password,
		&userPo.Phone,
		&userPo.Email,
		&userPo.Gender,
		&userPo.Status,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get user by account: %w", err)
	}

	return &entry.User{
		Id:      userPo.Id,
		Name:    userPo.Name,
		Account: userPo.Account,
		Phone:   userPo.Phone,
		Email:   userPo.Email,
		Gender:  userPo.Gender,
		Status:  userPo.Status,
	}, nil
}

func (u *UserDomainGatewayImpl) GetUserByEmail(email string) (*entry.User, error) {
	log.Printf("GetUserByEmail called with email: %s", email)
	var userPo po.UserPO

	query := `
		SELECT id, name, account, password, phone, email, gender, status
		FROM users
		WHERE email = $1`

	err := u.db.QueryRow(query, email).Scan(
		&userPo.Id,
		&userPo.Name,
		&userPo.Account,
		&userPo.Password,
		&userPo.Phone,
		&userPo.Email,
		&userPo.Gender,
		&userPo.Status,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get user by email: %w", err)
	}

	return &entry.User{
		Id:      userPo.Id,
		Name:    userPo.Name,
		Account: userPo.Account,
		Phone:   userPo.Phone,
		Email:   userPo.Email,
		Gender:  userPo.Gender,
		Status:  userPo.Status,
	}, nil
}

func (u *UserDomainGatewayImpl) GetUserByPhone(phone string) (*entry.User, error) {
	log.Printf("GetUserByPhone called with phone: %s", phone)
	var userPo po.UserPO

	query := `
		SELECT id, name, account, password, phone, email, gender, status
		FROM users
		WHERE phone = $1`

	err := u.db.QueryRow(query, phone).Scan(
		&userPo.Id,
		&userPo.Name,
		&userPo.Account,
		&userPo.Password,
		&userPo.Phone,
		&userPo.Email,
		&userPo.Gender,
		&userPo.Status,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get user by phone: %w", err)
	}

	return &entry.User{
		Id:      userPo.Id,
		Name:    userPo.Name,
		Account: userPo.Account,
		Phone:   userPo.Phone,
		Email:   userPo.Email,
		Gender:  userPo.Gender,
		Status:  userPo.Status,
	}, nil
}

func (u *UserDomainGatewayImpl) GetUserByName(name string) (*entry.User, error) {
	log.Printf("GetUserByName called with name: %s", name)
	var userPo po.UserPO

	query := `
		SELECT id, name, account, password, phone, email, gender, status
		FROM users
		WHERE name = $1`

	err := u.db.QueryRow(query, name).Scan(
		&userPo.Id,
		&userPo.Name,
		&userPo.Account,
		&userPo.Password,
		&userPo.Phone,
		&userPo.Email,
		&userPo.Gender,
		&userPo.Status,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get user by phone: %w", err)
	}

	return &entry.User{
		Id:      userPo.Id,
		Name:    userPo.Name,
		Account: userPo.Account,
		Phone:   userPo.Phone,
		Email:   userPo.Email,
		Gender:  userPo.Gender,
		Status:  userPo.Status,
	}, nil
}
